#include <DynamicList.h>
#include <LinkStack.h>
#include <BTree.h>
#include <DTString.h>
#include <RangeArray.h>
#include "gtest/gtest.h"
using namespace std;
using namespace DTLib;

namespace {

    TEST(DynamicList, all)
    {
        DTLib::DynamicList<int> dynamicList(3);

        EXPECT_EQ(dynamicList.capacity(), 3);
        EXPECT_EQ(dynamicList.length(), 0);

        for(int i=1; i<4; i++) {
            ASSERT_TRUE(dynamicList.insert(i));  //testcase: insert
        }

        EXPECT_EQ(dynamicList.length(), 3);

        for(int i=0; i<dynamicList.length(); i++) {
            EXPECT_EQ(dynamicList[i], i+1);
        }

        ASSERT_FALSE(dynamicList.insert(4, 4));

        for(int i=0; i<3; i++) {
            EXPECT_EQ(dynamicList[i], i+1);
        }

        ASSERT_TRUE(dynamicList.remove(1)); //testcase: remove

        EXPECT_EQ(dynamicList.length(), 2);
        EXPECT_EQ(dynamicList[0], 1);
        EXPECT_EQ(dynamicList[1], 3);

        EXPECT_THROW(dynamicList[2], DTLib::IndexOutOfBoundsException);

        ASSERT_FALSE(dynamicList.remove(5));

        //testcase: set
        ASSERT_TRUE(dynamicList.set(1, 2));

        ASSERT_FALSE(dynamicList.set(2, 3));

        //testcase: get
        int val = 0;
        ASSERT_TRUE(dynamicList.get(0, val));
        ASSERT_EQ(val, 1);
        ASSERT_TRUE(dynamicList.get(1, val));
        ASSERT_EQ(val, 2);
        ASSERT_FALSE(dynamicList.get(2, val));


        EXPECT_EQ(dynamicList.find(2), 1);

        EXPECT_NE(dynamicList.find(2), -1);

        // testcase: find
        EXPECT_EQ(dynamicList.find(3), -1 );

        // testcase: resize
        dynamicList.resize(4);
        EXPECT_EQ(dynamicList.capacity(), 4);
        EXPECT_EQ(dynamicList.length(), 2);
        EXPECT_EQ(dynamicList[0], 1);
        EXPECT_EQ(dynamicList[1], 2);


        dynamicList.resize(1);
        EXPECT_EQ(dynamicList.capacity(), 1);
        EXPECT_EQ(dynamicList.length(), 1);
        EXPECT_EQ(dynamicList[0], 1);
        EXPECT_THROW(dynamicList[1], DTLib::IndexOutOfBoundsException);

        // testcase: clear
        dynamicList.clear();
        EXPECT_EQ(dynamicList.length(), 0);
    }

    TEST(LinkStack, all) {
        LinkStack<int> stack;

        for(int i=1; i<=3; i++) {
            stack.push(i);
        }

        EXPECT_EQ(stack.size(), 3);
        EXPECT_EQ(stack.top(), 3);

        stack.pop();

        EXPECT_EQ(stack.size(), 2);
        EXPECT_EQ(stack.top(), 2);

        stack.pop();

        EXPECT_EQ(stack.size(), 1);
        EXPECT_EQ(stack.top(), 1);

        stack.pop();

        EXPECT_EQ(stack.size(), 0);
        EXPECT_THROW(stack.top(), InvalidOperationException);
        EXPECT_THROW(stack.pop(), InvalidOperationException);

    }

    TEST(BinTree, all) {
        BTree<int> bt;
        BTreeNode<int>* node = NULL;

        bt.insert(1, NULL);

        node = bt.root();
        bt.insert(2, node);
        bt.insert(3, node);

        node = bt.find(2);
        bt.insert(4, node, RIGHT);
        bt.insert(5, node, LEFT);

        node = bt.find(3);
        bt.insert(6, node, RIGHT);


        EXPECT_EQ(bt.height(), 3);
        EXPECT_EQ(bt.count(), 6);
        EXPECT_EQ(bt.degree(), 2);

        int result[6] = {1, 2, 3, 5, 4, 6};
        int index = 0;
        for(bt.begin(); !bt.end(); bt.next())
        {
            EXPECT_EQ(bt.current(), result[index]);
            index++;
        }

        bt.remove(2);

        EXPECT_EQ(bt.height(), 3);
        EXPECT_EQ(bt.count(), 3);
        EXPECT_EQ(bt.degree(), 1);

        int result_[6] = {1, 3, 6};
        int index_ = 0;

        for(bt.begin(); !bt.end(); bt.next())
        {
            EXPECT_EQ(bt.current(), result_[index_]);
            index_++;
        }
    }

    TEST(String, all) {
        const char* s = "DTLib";
        String hello = "Hello: ";
        String str;
        EXPECT_EQ(str.length(), 0);

        str.insert(hello);

        EXPECT_EQ(str.length(), 7);

        str += s;

        EXPECT_STREQ(str.str(), "Hello: DTLib");

        int index = str.indexOf(s);
        EXPECT_EQ(index, 7);

        EXPECT_STREQ(str.sub(index).str(), "DTLib");
        str.replace(s, "Joran");
        EXPECT_STREQ(str.str(), "Hello: Joran");
    }

    TEST(RangeArray, all) {
        RangeArray<double> a(-3, 5);

        EXPECT_EQ(-3, a.lower());

        EXPECT_EQ(5, a.upper());

        EXPECT_EQ(a.length(), a.upper()- a.lower() + 1);

        for (int i = a.lower(); i <= a.upper(); ++i) {
            a[i] = i / 10.0;
        }

        for(int i= a.lower(); i<= a.upper(); i++) {
            EXPECT_DOUBLE_EQ(a[i], i / 10.0);
        }

        RangeArray<double>& b = a;

        ASSERT_TRUE(b.set(-3, 0.4));

        double vv = 0.0;
        ASSERT_TRUE(b.get(-3, vv));
        EXPECT_DOUBLE_EQ(vv, 0.4);

        ASSERT_FALSE(b.set(-4, 0.4));
        double v4;
        ASSERT_FALSE(b.get(-4, v4));
        const RangeArray<double >& c = a;

        EXPECT_THROW(c[-4], IndexOutOfBoundsException);
    }
}
